<template>
  <div class="chatBox">
    <div class="chat">
      <div class="right">
        <div class="oner" ref="messageBox">
          <ul :key="recordKey">
            <li
              :class="[index % 2 == 0 ? 'user' : 'api']"
              v-for="(item, index) in historyMessage"
              :key="index"
            >
              <div class="message-content" v-if="index % 2 == 0">
                {{ item.message }}
              </div>
              <div
                class="message-success_content"
                v-if="index % 2 != 0 && item.type == 'success'"
              >
                <div style="margin-right: 15px">
                  <img :src="item.logo" alt="" class="aiLogo" />
                  <!-- <span>{{ getLogoUrl }}</span> -->
                </div>
                <Markdown
                  ref="mark"
                  :source="item.message"
                  :loading="loading"
                  :executeSqlData="executeSqlData"
                />
              </div>
              <div
                class="message-success_content"
                v-if="index % 2 != 0 && item.type == 'error'"
              >
                <div style="margin-right: 15px">
                  <img :src="item.logo" alt="" class="aiLogo" />
                </div>
                <p style="color: red; margin: 0">
                  {{ item.message }}
                </p>
              </div>
            </li>
            <li v-if="loading">
              <div>
                <img
                  style="height: 60px"
                  src="@/assets/ai_img/icon/loading.gif"
                  alt="生成中"
                />
              </div>
            </li>
          </ul>
        </div>
      </div>
    </div>
    <div class="chat-input-container" tabindex="0" data-testid="chat_input">
      <div class="chat-input grid-container">
        <div class="grid-input-area">
          <div
            class="container-AilALM flow-xs54Ev input custom-scrollbar-xZDNG1 semi-input-textarea-wrapper"
          >
            <textarea
              ref="inputRef"
              id="chatMessages"
              dir="ltr"
              v-model="messageValue"
              rows="1"
              autocomplete="off"
              data-testid="chat_input_input"
              cols="20"
              class="semi-input-textarea semi-input-textarea-autosize"
              placeholder="发消息"
              @keydown="handleKeydown"
              @input="handleInputMessage"
            ></textarea>
          </div>
          <div class="line"></div>
          <button
            id="flow-end-msg-send"
            aria-disabled="false"
            aria-label="发送"
            data-testid="chat_input_send_button"
            aria-describedby="9du7ipz"
            tabindex="0"
            data-popupid="9du7ipz"
            class="semi-button semi-button-primary send-btn-fDrkYV semi-button-with-icon semi-button-with-icon-only"
            type="button"
            @click="handleSendMessage"
          >
            <span class="semi-button-content"
              ><span role="img" class="semi-icon semi-icon-default"
                ><svg
                  xmlns="http://www.w3.org/2000/svg"
                  width=".7em"
                  height=".7em"
                  fill="currentColor"
                  viewBox="0 0 28 28"
                  :style="{
                    color: messageValue.length == 0 ? '#aaa' : '#06f',
                  }"
                >
                  <path
                    d="M14.007 28q-2.881 0-5.418-1.11a14.3 14.3 0 0 1-4.453-3.026 14.5 14.5 0 0 1-3.04-4.453Q0 16.875 0 13.993q0-2.868 1.095-5.404Q2.191 6.053 4.121 4.12A14.5 14.5 0 0 1 8.59 1.095Q11.124 0 13.993 0t5.404 1.095q2.536 1.096 4.467 3.026A14.2 14.2 0 0 1 26.89 8.59Q28 11.124 28 13.993q0 2.881-1.095 5.418a14.3 14.3 0 0 1-3.027 4.453 14.2 14.2 0 0 1-4.467 3.026Q16.876 28 14.007 28m.015-6.917q.518 0 .835-.317.332-.332.332-.836v-6.816l-.13-2.969 1.37 1.672 1.599 1.643q.316.33.807.331.475 0 .792-.303a.99.99 0 0 0 .332-.763q0-.475-.332-.807L14.944 7.22q-.433-.447-.922-.447-.476 0-.908.447L8.43 11.918q-.317.317-.317.807 0 .461.317.763.318.303.778.303.49 0 .807-.331l1.629-1.658 1.326-1.642-.116 2.954v6.816q0 .504.332.836.331.317.836.317"
                  ></path></svg></span
            ></span>
          </button>
        </div>
      </div>
    </div>
    <div class="fn_bottom">
      <div class="fn_bottom-main">
        <p>转换</p>
        <p>执行</p>
        <p>错误信息</p>
        <p>堆栈错误信息</p>
      </div>
    </div>

    <!-- <div class="grammar">
      <el-checkbox v-model="grammarChecked" @change="handleCheckbox"
        ><span class="label">语法兼容转换</span>
        <el-select
          v-if="grammarChecked"
          style="width: 100%"
          v-model="grammarCheckedValue"
          placeholder="请选择语法兼容库"
        >
          <el-option
            v-for="item in dict.type.grammar_compatible_conversion"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
      </el-checkbox>
      <span class="a" @click="previewTipsDialog = true">查看提示词</span>
      <span class="errorTips" @click="previewErrorTipsDialog = true"
        >报错信息</span
      >
    </div> -->
    <!-- <div class="tips">
      <p class="label">
        提示语句
        <span class="changeTips" @click="getKeyword"
          >换一批
          <svg
            t="1730871261743"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="4445"
            width="12"
            height="12"
          >
            <path
              d="M949.252087 430.532547c-9.240455-7.446599-22.75526-5.965875-30.169113 3.328815l-36.743856 46.075385c-1.208525-17.817808-3.606131-35.751249-7.338129-53.722552C829.114916 204.421786 613.312942 62.124919 393.013537 108.309798 172.691619 154.50798 31.294239 371.70165 77.179288 593.470523c45.88505 221.791385 261.688048 364.101555 482.009965 317.880861 80.081896-16.785292 148.922774-56.816007 202.800869-110.918205 0.199545-0.198521 0.401136-0.355087 0.602727-0.578168 0.956791-0.979304 1.290389-2.113127 2.248204-3.115967 1.578961-2.670829 2.714831-5.855358 2.714831-9.171893 0-9.82067-7.92346-17.790178-17.675568-17.790178-5.254677 0-9.842159 2.405793-13.093203 6.078439l-0.130983-0.11154c-48.916083 49.047066-111.676475 85.202521-184.344518 100.432387-199.506846 41.833781-394.937864-87.050612-436.482049-287.880593-41.566698-200.809515 86.493933-397.531945 285.999756-439.364703 199.506846-41.822524 394.937864 87.073124 436.480003 287.880593 3.207042 15.446807 5.425569 30.855752 6.712889 46.165436l-44.603871-36.034704c-9.262968-7.470135-22.753213-5.966898-30.169113 3.317559-7.435343 9.317203-5.944386 22.898523 3.297093 30.390147 0.045025 0.022513 0.045025 0.022513 0.090051 0.022513l82.132602 66.39006c0.020466 0 0.065492 0.044002 0.086981 0.066515 4.692882 3.793396 10.480702 5.266957 16.016789 4.590552 5.539156-0.555655 10.861372-3.25616 14.617929-7.964392 0.021489-0.021489 0.045025-0.066515 0.045025-0.066515l65.944921-82.71998c0.021489-0.021489 0.021489-0.021489 0.065492-0.045025C959.95894 451.606515 958.492542 438.012915 949.252087 430.532547z"
              fill="#555555"
              p-id="4446"
            ></path>
          </svg>
        </span>
      </p>
      <div class="tips-content">
        <el-checkbox-group
          v-model="checkList"
          style="display: flex; flex-wrap: wrap"
        >
          <el-checkbox
            v-for="item in keywordList"
            :key="item"
            :label="item"
            class="tips-item"
          />
        </el-checkbox-group>
      </div>
    </div>

    <el-dialog
      title="提示词预览"
      width="800px"
      :visible.sync="previewTipsDialog"
    >
      <div>
        <p style="white-space: pre-wrap" class="message-content">
          "{{ getMessageValue() }}
        </p>
      </div>
    </el-dialog>

    <el-dialog
      title="错误信息"
      width="800px"
      :visible.sync="previewErrorTipsDialog"
    >
      <div>
        <p style="white-space: pre-wrap;height:540px;" class="errMessageTips">
          {{ errorMessage }}
        </p>
      </div>
    </el-dialog> -->
  </div>
</template>
<script>
import { doubao, tongyi, wenxin, chatgpt, zhipu } from "@/assets/ai_img/index";
import Markdown from "@/components/marckdown";
import {
  sendAiMessage,
  getKeyword,
  convertSqlPush,
} from "@/api/console/belfAi";
export default {
  name: "migrationReportAiChat",
  components: {
    Markdown,
  },
  props: ["aiModelValue", "executeSqlData", "databaseInfo", "taskType"],
  dicts: ["grammar_compatible_conversion"],
  data() {
    return {
      historyMessage: [],
      messageValue: "",
      loading: false,
      grammarChecked: false,
      grammarCheckedValue: "",
      systemValue: "你是一名知识丰富的DBA",
      checkList: [],
      recordKey: null,
      keywordList: [],
      previewTipsDialog: false,
      previewErrorTipsDialog: false,
      errorMessage: "",
    };
  },
  async mounted() {
    this.getKeyword();
  },
  created() {
    window.addEventListener("resize", this.calculateInputHeight);
    // console.log(JSON.parse(localStorage.getItem("migrationReportAi")));
    this.errorMessage = JSON.parse(
      localStorage.getItem("migrationReportAi")
    ).errors;
  },
  methods: {
    async convertSql() {
      const res = await convertSqlPush({
        id: "1",
        name: "1",
        title: "1",
        convertType: "1",
        sourceType: "MySql",
      });
      //           /**  */
      // private Long id;
      // /** 任务名称 */
      // @Excel(name = "任务名称")
      // private String name;
      // /** 标题 */
      // @Excel(name = "标题")
      // private String title;
      // /** 转换类型 */
      // @Excel(name = "转换类型")
      // private String convertType;
      // /** 源类型 */
      // @Excel(name = "源类型")
      // private String sourceType;
      // /** 源版本 */
      // @Excel(name = "源版本")
      // private String sourceVersion;
      // /** 源配置 */
      // @Excel(name = "源配置")
      // private String sourceConf;
      // /** 源SQL */
      // @Excel(name = "源SQL")
      // private String sourceSql;
      // /** 目标类型 */
      // @Excel(name = "目标类型")
      // private String sinkType;
      // /** 目标版本 */
      // @Excel(name = "目标版本")
      // private String sinkVersion;
      // /** 目标配置 */
      // @Excel(name = "目标配置")
      // private String sinkConf;
      // /** 目标SQL */
      // @Excel(name = "目标SQL")
      // private String sinkSql;
      // /** 对象类型 */
      // @Excel(name = "对象类型")
      // private String objecType;
      // /** 关键词信息 */
      // @Excel(name = "关键词信息")
      // private String keyInfo;
      // /** 会话记录 */
      // @Excel(name = "会话记录")
      // private String sessionLog;
      // /** 会话状态 */
      // @Excel(name = "会话状态")
      // private String sessionStatus;
    },
    async getKeyword() {
      const { taskId, type } = JSON.parse(
        localStorage.getItem("migrationReportAi")
      );
      const res = await getKeyword({
        taskId,
        objectType: type,
      });
      this.keywordList = [];
      res.data.forEach((f, i) => {
        if (i != 0) {
          this.keywordList.push(f);
        }
      });
    },
    handleCheckbox(_v) {
      if (_v) {
        this.grammarCheckedValue =
          this.dict.type.grammar_compatible_conversion[0].value;
      } else {
        this.grammarCheckedValue = null;
      }
    },
    handleInputMessage(e) {
      const inputElement = this.$refs.inputRef;
      if (inputElement === null) {
        return;
      }
      this.$nextTick(() => {
        const computedInputStyle = window.getComputedStyle(inputElement);
        const maxHeightString =
          computedInputStyle.getPropertyValue("max-height");
        const maxHeight = parseInt(maxHeightString);
        inputElement.setAttribute("style", `height: auto; overflow-y: hidden;`);
        inputElement.setAttribute(
          "style",
          `height: ${inputElement.scrollHeight}px; ${
            inputElement.scrollHeight > maxHeight
              ? `overflow-y: auto;`
              : "overflow-y: hidden;"
          }`
        );
      });
    },
    handleKeydown(event) {
      this.handleInputMessage();
      if (event.key === "Enter" && !event.shiftKey) {
        event.preventDefault();

        this.handleSendMessage();
      }
    },
    scrollToBottom() {
      this.$nextTick(() => {
        const scrollElem = this.$refs.messageBox;
        scrollElem.scrollTo({
          top: scrollElem.scrollHeight,
          behavior: "smooth",
        });
      });
    },
    getLogoUrl() {
      const logoMap = {
        ERNIE: wenxin,
        gpt: chatgpt,
        Doubao: doubao,
        qwen: tongyi,
        GLM: zhipu,
      };

      for (const key in logoMap) {
        if (this.aiModelValue.includes(key)) {
          return logoMap[key];
        }
      }

      return false;
    },
    async handleSendMessage() {
      let that = this;
      // console.log(this.messageValue);
      if (
        this.messageValue.replace(/[\r\n\s]/g, "").length < 1 ||
        this.loading
      ) {
        return;
      }
      this.loading = true;
      let value = this.getMessageValue();
      this.messageValue = "";
      this.handleInputMessage();
      this.historyMessage.push({
        type: "user",
        message: value,
      });
      this.scrollToBottom();
      const res = await sendAiMessage({
        model: this.aiModelValue,
        stream: true,
        messages: that.getMessage(),
      });
      if (res.error) {
        this.historyMessage.push({
          type: "error",
          message: res.error.message,
          logo: this.getLogoUrl(),
        });
        this.loading = false;
        return;
      }
      that.historyMessage.push({
        type: "success",
        message: "",
        logo: that.getLogoUrl(),
      });
      const reader = res.getReader();
      const decoder = new TextDecoder("utf-8");
      this.loading = false;
      let buffer = "";
      function readStream() {
        reader.read().then(({ done, value }) => {
          if (done) {
            if (
              that.historyMessage[that.historyMessage.length - 1].message
                .length == 0
            ) {
              that.historyMessage[that.historyMessage.length - 1] = {
                type: "error",
                message: "次数不足，请切换AI源~~",
                logo: that.getLogoUrl(),
              };
              that.recordKey = Math.random();
            }
            that.$emit("getHistory-event", that.historyMessage);
            console.log("读取流结束");
            return;
          }
          buffer += decoder.decode(value, { stream: true });
          const events = buffer
            .split("\n\n")
            .filter((event) => event.trim() !== "");
          const remaining = buffer.slice(buffer.lastIndexOf("\n\n") + 2);
          events.forEach((event) => {
            const lines = event.split("\n");
            const eventData = {};
            // 获取历史记录
            lines.forEach((line) => {
              const [key, ...values] = line.split(": ");
              eventData[key] = values.join(": ");
            });
            if (eventData.data) {
              try {
                const jsonEvent = JSON.parse(eventData.data);
                that.historyMessage[that.historyMessage.length - 1].message +=
                  jsonEvent.choices[0].delta.content || "";
                that.scrollToBottom();
              } catch (error) {
                return;
              }
            }
          });

          buffer = remaining;
          readStream();
        });
      }
      readStream();
    },
    getMessageValue() {
      const { sourceDdl, sinkDdl } = JSON.parse(
        localStorage.getItem("migrationReportAi")
      );
      const lengthBool = this.messageValue.length > 0;
      const { taskType } = this.$props.databaseInfo;
      let basic = `请将以下${taskType.split("-")[0]}的创建存储过程的SQL换为${
        this.grammarCheckedValue || taskType.split("-")[1]
      }的创建${this.$props.taskType}的SQL： \n ' ${
        sourceDdl || sinkDdl
      } ' \n 转换要求：`;
      basic += lengthBool ? `\n 1.${this.messageValue}` : "";
      this.checkList.forEach((f, i) => {
        f = f.replace(/\n/g, "");
        basic += `\n ${length ? i + 2 : i + 1}.${f} `;
      });
      return basic;
    },
    getMessage() {
      let arr = [];
      this.historyMessage.forEach((f, i) => {
        arr.push({
          role: i % 2 == 0 ? "user" : "system",
          content: f.message,
        });
      });
      arr.unshift({
        role: "system",
        content: this.systemValue,
      });
      // arr[arr.length - 1].content = '测试重组数据'
      // console.log();
      return arr;
    },
  },
};
</script>

<style lang="scss" scoped>
.chatBox {
  width: 100%;
  height: 100%;
  overflow: hidden;

  .label {
    font-weight: 600;
    color: #000;
    font-size: 14px;
    margin: 0;
    margin-right: 10px;
    .changeTips {
      float: right;
      font-weight: 500;
      color: #555;
      font-size: 12px;
      cursor: pointer;
    }
  }

  .tips {
    width: 95%;
    margin: 0.5rem auto;

    .tips-item {
      width: 40%;
      margin: 10px 0 0 25px;
    }
  }

  .grammar {
    width: 95%;
    margin: 0.5rem auto;
    height: 30px;

    .a {
      color: rgb(68, 68, 255);
      float: right;
      cursor: pointer;
      font-size: 12px;
    }
  }

  .chat {
    width: 95%;
    height: 85%;
    border-radius: 5px;
    margin: 0.5rem auto;
    box-shadow: 0 0 5px #ccc;
    background-color: #fff;

    ul {
      list-style-type: none;
      padding: 0;
      margin: 0;
    }
  }
  .fn_bottom {
    width: 95%;
    height: 50px;
    margin: 10px auto;
    background: #fff;

    .fn_bottom-main{
      display: flex;
      p{
        margin: 0 15px;
      }
    }
  }
}
</style>

<style scoped>
.user {
  text-align: right;
}

.user > div {
  text-align: left;
  word-break: break-word;
  white-space: pre-wrap;
  border-radius: 15px;
  padding: 5px 10px;
  font-size: 14px;
  display: inline-block;
  width: auto;
  color: #121512;
  background-color: rgb(245, 245, 245);
}

p {
  font: 400 16px / 24px Inter, -apple-system, BlinkMacSystemFont, Segoe UI,
    SF Pro SC, SF Pro Display, SF Pro Icons, PingFang SC, Hiragino Sans GB,
    Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif;
}

.chartBox {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.chartBox {
  display: flex;
}

.left {
  width: 25%;
  background-color: rgb(244, 244, 244);
  height: 100%;
  border-top-right-radius: 10px;
  border-bottom-right-radius: 10px;
  padding-top: 20px;
}

.left > .chart-select {
  padding: 0 5px;
  width: 80%;
  height: 50px;
  margin: 30px auto;
  border: 1px solid rgb(192, 196, 204);
}

.send-btn-fDrkYV svg {
  transition: color 0.2s linear;
}

.right {
  width: 100%;
  height: 100%;
  /* text-align: center; */
  overflow: auto;
  position: relative;
  background-color: #fff;
}

.info {
  position: absolute;
  bottom: 0;
}

.oner {
  height: 100%;
  padding: 15px;
  overflow: auto;
}

.chat-input-container {
  border: 1px solid rgb(229, 229, 229);
  background: #fff;
  border-radius: 5px;
  box-shadow: 0 6px 10px 0 rgba(42, 60, 79, 0.1);
  box-sizing: border-box;
  width: 95%;
  margin: 0 auto;
}

.grid-container {
  align-items: flex-end;
  display: grid;
  gap: 10px;
  grid-template-areas: "left-tools input-area right-tools";
  grid-template-columns: auto 1fr auto;
  grid-template-rows: auto;
  width: 100%;
}

.chat-input {
  background: #fff;
  border-radius: 220px;
  box-sizing: border-box;
  display: flex;
  width: 100%;
  padding: 5px 12px 5px 14px;
  position: relative;
}

.grid-container .grid-input-area {
  align-self: center;
  width: 100%;
  grid-area: input-area;
  display: flex;
  align-items: center;
}

.chat-input .input {
  background-color: transparent !important;
}

.chat-input .input {
  align-self: center;
  border-radius: 0 !important;
  border-width: 0 !important;
  caret-color: #0057ff;
  caret-color: #0057ff;
  flex: 1 1 !important;
  min-width: 0 !important;
  overflow-x: hidden !important;
  padding: 0 !important;
  width: 100% !important;
}

.container-AilALM.flow-xs54Ev.semi-input-textarea-wrapper .semi-input-textarea {
  border-radius: 12px;
  cursor: auto;
  font: 400 16px / 24px Inter, -apple-system, BlinkMacSystemFont, Segoe UI,
    SF Pro SC, SF Pro Display, SF Pro Icons, PingFang SC, Hiragino Sans GB,
    Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif;
  overflow-anchor: auto;
  overflow-y: auto;
  padding: 0 12px;
}

.chat-input .input .semi-input-textarea {
  max-height: 180px !important;
  min-width: 0px !important;
  padding: 0 0 0 0 !important;
}

.chat-input .input textarea {
  border-radius: 0 !important;
  color: #000;
  color: var(--color-neutral-100, #000);
}

.semi-input-textarea {
  background-color: transparent;
  border: 0 solid transparent;
  box-shadow: none;
  box-sizing: border-box;
  color: rgb(28, 31, 35);
  cursor: text;
  font: 400 16px / 24px Inter, -apple-system, BlinkMacSystemFont, Segoe UI,
    SF Pro SC, SF Pro Display, SF Pro Icons, PingFang SC, Hiragino Sans GB,
    Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif;
  font-size: 14px;
  line-height: 20px;
  outline: none;
  padding: 5px 12px;
  position: relative;
  resize: none;
  vertical-align: bottom;
  width: 100%;
}

.send-btn-fDrkYV,
.send-btn-fDrkYV svg {
  height: 28px;
  width: 28px;
}
.send-btn-fDrkYV {
  background-color: #f5f5f5;
  border: 0;
  border-radius: 18px;
  box-sizing: border-box;
  padding: 0;
}

.semi-button {
  cursor: pointer;
}

.line {
  width: 1px;
  height: 20px;
  background: rgba(0, 0, 0, 0.2);
  margin: 0 10px;
}

.api {
  margin: 10px 0;
}

.message-success_content {
  display: flex;
  margin: 25px 0;
}

.aiLogo {
  width: 25px;
  border-radius: 20px;
}

.message-content {
  font: 400 16px / 24px Inter, -apple-system, BlinkMacSystemFont, Segoe UI,
    SF Pro SC, SF Pro Display, SF Pro Icons, PingFang SC, Hiragino Sans GB,
    Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif;
}

.errorTips {
  color: red;
  margin: 0 10px;
  float: right;
  cursor: pointer;
  font-size: 12px;
}

.errMessageTips {
  width: 100%;
  overflow: auto;
  background: #2a313d;
  color: #ccc;
  height: 100%;
  padding: 10px;
  font-size: 14px;
}
</style>